SQLite Is Probably All You Need
Somewhere along the way, "set up the database" started to mean provisioning a managed Postgres cluster, a connection pooler, and a migrations pipeline — before writing a single query. For a huge class of applications, all of that is replacing a file on disk that would have worked fine.
What SQLite actually is
SQLite isn't a toy version of a real database. It's the most deployed database engine on the planet — it's in your phone, your browser, your car, and probably your washing machine. It implements most of SQL, it's ACID-compliant, and it has one of the most rigorously tested codebases in the industry, with tests outweighing source code by several hundred to one.
The difference from Postgres isn't quality. It's architecture: SQLite runs inside your process and reads a local file. No network hop, no connection pool, no auth handshake. A query that needs one row takes microseconds, not milliseconds.
The scaling myth
The standard objection is "it won't scale." Let's be specific about what scaling means for most projects:
- Reads: SQLite handles tens of thousands of reads per second on ordinary hardware
- Writes: with WAL mode enabled, one writer and many readers proceed without blocking each other
- Data size: the file format is comfortable into the hundreds of gigabytes
The honest constraint is concurrent writers across multiple machines. If you have that problem, you'll know — and you can migrate then, with real usage data to guide the schema. Most side projects, internal tools, and small products never get there.
Turn on the good settings
Out of the box SQLite is conservative. Two pragmas change everything:
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;WAL mode is the big one — readers stop blocking the writer. Set a busy timeout while you're at it, and back the file up with sqlite3 app.db ".backup backup.db" on a cron job. That's the whole ops story.
When you genuinely need more
Multiple app servers writing to shared state, row-level permissions enforced in the database, extensions your workload depends on — those are real reasons to run a server database, and you should. The point isn't that SQLite wins every time. The point is that the default has flipped: start with the file, and let the application earn the cluster.